#pragma once
#include "Reactor.hpp"
#include <vector>
#include "Util.hpp"

// 1:本次读取sock的数据读完
//-1：读取出错；0：对端关闭连接
static int RecverCore(int sock, std::string &inbuffer)
{
    char buffer[128];

    while (true) //循环目的就是为了读取完sock的数据
    {
        ssize_t sz = recv(sock, buffer, sizeof(buffer) - 1, 0);
        if (sz > 0)
        {
            /*这里读取当做字符串看待，其实不太好，因为读取的内容，可能本身就包含\0,比如一张图片
             * 但是，为了简单化处理，这里也是当做字符串看待了
             */
            //读取一次成功
            buffer[sz] = '\0';
            inbuffer += buffer;
        }
        else if (sz == 0)
            return 0;
        else
        {
            if (errno == EINTR) //读取时候被中断了，那么再次重新读就行
            {
                //虽然在非阻塞IO中，这种情况概率及其低，但是也要处理
                continue;
            }
            // 1.读完，底层没有数据可以读，返回sz<0
            if (errno == EAGAIN || errno == EWOULDBLOCK)
            {
                return 1; // success
            }
            // 2.读出错了
            return -1;
        }
    }
}

int Recver(Event *evp)
{
    std::cout << "Recver have been called" << std::endl;
    // 1.真正的读取
    int retsult = RecverCore(evp->sock, evp->inbuffer);
    if (retsult <= 0) //出错了，那么就调用该sock的回调函数：进行差错处理
    {
        if (evp->errer)
            evp->errer(evp);
        return -1;
    }

    //////////////////////////////////////////////////
    //上下两层其实是可以分层...但是这里为了方便就不分了//
    //////////////////////////////////////////////////
    // 2.分包-->因为有可能你读取时候，可能只读到有半个报文之类的，所以我们只要读到的报文一个或多个报文
    //也就是解决粘包问题
    //请求：1+2X3+4X
    std::vector<std::string> tokens;
    //这就是自己定义字符，解决年粘包问题
    std::string sep = "X";
    SplitSegment(evp->inbuffer, &tokens, sep); //将拆分成功一个一个完整报文存入
    // 3.反序列化-->针对一个报文-->提取有效信息参与计算或存储信息
    for (auto &seg : tokens) // tokens的每个元素局是:1+2 2+3 ...
    {
        std::string data1, data2;
        if (Deserialize(seg, &data1, &data2)) //和业务强相关的操作
        {
            // 4.业务逻辑处理-->得到结果
            int x = atoi(data1.c_str());
            int y = atoi(data2.c_str());
            int z = x + y;

            // 5.构建响应---->不应该直接send出去，而是添加到outbuffer
            // 2+3X--->2+3=5X
            std::string res = data1;
            res += "+";
            res += data2;
            res += "=";
            res += std::to_string(z);
            res += sep;

            //将响应添加到自己的sock发送缓冲区
            //而真正的发送这个动作，是Reactor帮我们做的
            evp->outbuffer += res;
        }
    }

    // 6.发送
    // 写事件基本大概率都是就绪的，可是用户不一定会就绪
    // （这个场景就是：用户请求报文没发给服务器，服务器即使就绪，也接受不到你的报文）
    // 对于写事件就绪，大部分慢的不是服务器，一般都是用户发送慢的原因呗；
    // 重点： 对于写事件就绪，我们一般都是按需设置（也就是用户必须准备好数据）

    if (!evp->outbuffer.empty()) //只要我们打开写事件就绪，dispatch函数会自动帮我们派发写事件的函数
        evp->R->EableRW(evp->sock, true, true);
    return 0;
}
static int SenderCore(int sock, std::string &outbuffer)
{
    int total = 0; // 累计发送的数据
    int size = outbuffer.size();
    const char *start = outbuffer.c_str();

    while (true)
    {
        ssize_t sz = send(sock, start + total, size - total, 0);
        if (sz > 0)
        {
            total += sz;
            if (total == size)
            {
                outbuffer.clear();
                return 1; //表示发完
            }
        }
        else
        {
            if (errno == EINTR)
                continue;
            //数据没发完，但是也不可以再发；该情况是对方接受缓冲区满了，即使发送缓冲区有数据，也不可以再次发送
            if (errno == EAGAIN || errno == EWOULDBLOCK)
            {
                outbuffer.erase(0, total);
                return 0;
            }
        }
        return -1; //发送失败！
    }
}
int Sender(Event *evp)
{
    std::cout << "Sender have been called" << std::endl;
    int result = SenderCore(evp->sock, evp->outbuffer);
    if (result == 1) //发送完毕，关闭写事件
        evp->R->EableRW(evp->sock, true, false);
    else if (result == 0) //数据没发完
        evp->R->EableRW(evp->sock, true, true);
    else
    {
        if (evp->errer) //出错就调用差错处理函数呗
            evp->errer(evp);
    }
}
int Errorer(Event *evp)
{
    evp->R->DeleteEvent(evp);
    std::cout << "Errorer have been called..." << std::endl;
}